//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "DatasetModelEvaluation.h"
#include "InstanceModelEvaluation.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fstream>
#include <iostream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define MAX_SIZE 500000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace InstanceEvaluationByModel {

  bool EqualPattern (TNode <PatternWeight>* patternWeight, void* ref) {
    
    return (!strcmp(patternWeight->Info()->Pattern()->Out(), ((String*)ref)->Out()))?true:false;

  }
  
  bool EqualType (TNode <PatternWeight>* patternWeight, void* ref) {

    return (!strcmp(patternWeight->Info()->Type()->Out(), ((String*)ref)->Out()))?true:false;

  }
  
}  
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DatasetModelEvaluation::DatasetModelEvaluation () {

  this->filenameARFFIn                     = new String ();
  this->arffData                           = new ArffObject ();
  this->bindingSitePrediction              = new ListBindingSitePredictionWeighted ();
  this->evaluation                         = new TListE <InstanceModelEvaluation> ();
  this->filenameOut                        = new String ();
  
  this->toString                           = new String ();

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DatasetModelEvaluation::DatasetModelEvaluation (const DatasetModelEvaluation& datasetModelEvaluation) {

  this->filenameARFFIn                     = new String (datasetModelEvaluation.filenameARFFIn);
  this->arffData                           = new ArffObject (datasetModelEvaluation.arffData);
  this->bindingSitePrediction              = new ListBindingSitePredictionWeighted (datasetModelEvaluation.bindingSitePrediction);
  this->evaluation                         = new TListE <InstanceModelEvaluation> (datasetModelEvaluation.evaluation);
  this->filenameOut                        = new String (datasetModelEvaluation.filenameOut);

  this->toString                           = new String (datasetModelEvaluation.toString);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DatasetModelEvaluation::DatasetModelEvaluation (const DatasetModelEvaluation* datasetModelEvaluation) {

  this->filenameARFFIn                     = new String (datasetModelEvaluation->filenameARFFIn);
  this->arffData                           = new ArffObject (datasetModelEvaluation->arffData);
  this->bindingSitePrediction              = new ListBindingSitePredictionWeighted (datasetModelEvaluation->bindingSitePrediction);
  this->evaluation                         = new TListE <InstanceModelEvaluation> (datasetModelEvaluation->evaluation);
  this->filenameOut                        = new String (datasetModelEvaluation->filenameOut);
  
  this->toString                           = new String (datasetModelEvaluation->toString);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DatasetModelEvaluation::~DatasetModelEvaluation () {

  if (this->filenameARFFIn)        delete this->filenameARFFIn;
  if (this->arffData)              delete this->arffData;
  if (this->bindingSitePrediction) delete this->bindingSitePrediction;
  if (this->evaluation)            delete this->evaluation;
  if (this->filenameOut)           delete this->filenameOut;
  if (this->toString)              delete this->toString;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DatasetModelEvaluation::FilenameARFFIn (String* filenameARFFIn) {

  if (filenameARFFIn)
    *(this->filenameARFFIn) = *filenameARFFIn;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DatasetModelEvaluation::ArffData (ArffObject* arffData) {

  if (arffData)
    *(this->arffData) = *arffData;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DatasetModelEvaluation::BindingSitePrediction (ListBindingSitePredictionWeighted* bindingSitePrediction) {

  if (bindingSitePrediction)
    *(this->bindingSitePrediction) = *bindingSitePrediction;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DatasetModelEvaluation::Evaluation (TListE <InstanceModelEvaluation>* evaluation) {

  if (evaluation)
    *(this->evaluation) = *evaluation;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DatasetModelEvaluation::FilenameOut (String* filenameOut) {

  if (filenameOut)
    *(this->filenameOut) = *filenameOut;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* DatasetModelEvaluation::FilenameARFFIn (void) {

  return this->filenameARFFIn;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ArffObject* DatasetModelEvaluation::ArffData (void) {

  return this->arffData;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListBindingSitePredictionWeighted* DatasetModelEvaluation::BindingSitePrediction (void) {

  return this->bindingSitePrediction;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <InstanceModelEvaluation>* DatasetModelEvaluation::Evaluation (void) {

  return this->evaluation;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* DatasetModelEvaluation::FilenameOut (void) {

  return this->filenameOut;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool DatasetModelEvaluation::LoadData (void) {

  if (!this->filenameARFFIn                     || !this->filenameARFFIn->Length()                         ||
      !this->arffData                           || !this->bindingSitePrediction                            ||
      !this->bindingSitePrediction->Scheme()    || !this->bindingSitePrediction->Scheme()->Length()        ||
      !this->bindingSitePrediction->XMLModels() || !this->bindingSitePrediction->XMLModels()->FilenameIn() ||
      !this->bindingSitePrediction->XMLModels()->FilenameIn()->Length())
    return false;

  this->arffData->Filename(this->filenameARFFIn);
  
  if (!this->arffData->LoadData())
    return false;

  if (!this->bindingSitePrediction->XMLModels()->LoadXMLFile())
    return false;

  if (!this->bindingSitePrediction->LoadWeight())
    return false;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool DatasetModelEvaluation::EvaluateWithModel (void) {

  if (!this->arffData->Data()                             || !this->bindingSitePrediction->Weights() || 
      !this->bindingSitePrediction->Weights()->Patterns() || !this->bindingSitePrediction->Weights()->Patterns()->Length())
    return false;
  
  this->evaluation->Clear();

  for (int i = 0; i < this->arffData->Domains()->Length(); i++) {
    
    float functionEvaluation = 0;
    int   foundPatterns      = 0;
    
    //cout << "Domain: " << this->arffData->Domains()->Get(i)->Out() << endl;
    
    for (int j = 1; j < this->arffData->Attributes()->Length() - 1; j++) {
      
      String patternToSearch;
      
      if      (!strncmp(this->arffData->Attributes()->Get(j)->Value()->Out(), "Seq.", 4)) patternToSearch.In(this->arffData->Attributes()->Get(j)->Value()->Out() + 4);
      else if (!strncmp(this->arffData->Attributes()->Get(j)->Value()->Out(), "CH.",  3)) patternToSearch.In(this->arffData->Attributes()->Get(j)->Value()->Out() + 3);
      else if (!strncmp(this->arffData->Attributes()->Get(j)->Value()->Out(), "PH.",  3)) patternToSearch.In(this->arffData->Attributes()->Get(j)->Value()->Out() + 3);
      else if (!strncmp(this->arffData->Attributes()->Get(j)->Value()->Out(), "SS.",  3)) patternToSearch.In(this->arffData->Attributes()->Get(j)->Value()->Out() + 3);
      else if (!strncmp(this->arffData->Attributes()->Get(j)->Value()->Out(), "MT.",  3)) patternToSearch.In(this->arffData->Attributes()->Get(j)->Value()->Out() + 3);
      else                                                                                patternToSearch.In(this->arffData->Attributes()->Get(j)->Value()->Out());
      
      PatternWeight* searchPatternWeight = this->bindingSitePrediction->Weights()->Patterns()->FirstOcurrence(InstanceEvaluationByModel::EqualPattern, &patternToSearch);
      if (searchPatternWeight) 
        if ((this->arffData->Data())[i][j - 1]) {
          functionEvaluation += (searchPatternWeight->Weight());
          foundPatterns++;
          //cout << "patternToSearch: " << patternToSearch.Out() << " - Weight: " << searchPatternWeight->Weight() << endl;
        }
      
    }

    String         correction ("Correction");
    PatternWeight* searchPatternWeight = this->bindingSitePrediction->Weights()->Patterns()->FirstOcurrence(InstanceEvaluationByModel::EqualType, &correction);
    
    if (searchPatternWeight) 
      functionEvaluation += searchPatternWeight->Weight();
    else {
      cout << "Error finding the Correction value!!!" << endl;
      continue;
    }
    
    InstanceModelEvaluation* newInstanceModelEvaluation = new InstanceModelEvaluation ();
    
    newInstanceModelEvaluation->Domain(this->arffData->Domains()->Get(i));
    newInstanceModelEvaluation->ValueSMOEvaluation(functionEvaluation);
    newInstanceModelEvaluation->NumberFoundPatterns(foundPatterns);
    newInstanceModelEvaluation->Classification(this->arffData->Classification()->Get(i));
    
    this->evaluation->Add(newInstanceModelEvaluation);
      
  }
  
  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool DatasetModelEvaluation::WriteResults (void) {
  
  if (!this->filenameOut || !this->filenameOut->Length() || !this->evaluation || !this->evaluation->Length())
    return false;
  
  ofstream file (this->filenameOut->Out());
  
  if (!file.is_open()) return false;
  
  this->evaluation->SetInitial();
  while (this->evaluation->SetNext())
    file << this->evaluation->GetCurrent()->ToString()->Out() << endl;
  
  file.close();
  
  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DatasetModelEvaluation DatasetModelEvaluation::operator= (const DatasetModelEvaluation& datasetModelEvaluation) {

  *(this->filenameARFFIn)         = *(datasetModelEvaluation.filenameARFFIn);
  *(this->arffData)               = *(datasetModelEvaluation.arffData);
  *(this->bindingSitePrediction)  = *(datasetModelEvaluation.bindingSitePrediction);
  *(this->evaluation)             = *(datasetModelEvaluation.evaluation);
  *(this->filenameOut)            = *(datasetModelEvaluation.filenameOut);
  
  *(this->toString)               = *(datasetModelEvaluation.toString);

  return *this;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
